﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Sgml.Validation;
using Engine.Sgml.Merging;
using Engine.Sgml.Validation.Rules;
using System.Diagnostics;

namespace Engine.Sgml.Allocation {
    internal sealed class BlockAllocator : IBlockAllocator {
        private InconsistentBlockAllocator blockAllocator;
        private TreeNodeNavigator nodeNavigator;

        public BlockAllocator(ValidationRuleCollection rules) {
            Guard.ArgumentNotNull(rules, "rules");
            blockAllocator = new InconsistentBlockAllocator();
            nodeNavigator = new TreeNodeNavigator(rules);
            }

        public void Allocate(BlockItem item, AllocationContext context) {
            for (int i = 0; i < item.InconsistentBlocks.Count; i++) {
                InconsistentBlock block = item.InconsistentBlocks[i];
                nodeNavigator.Reset(block);
                while (nodeNavigator.MoveToNext()) {
                    int blockItemsCount = block.Count;

                    IList<InconsistentBlock> unallocatedBlocks = blockAllocator.Allocate(block, nodeNavigator.Current, context);

                    if (unallocatedBlocks.Count > 0) {
                        // TODO: Trace information about this process
                        IBlockAllocator allocator = context.GetBlockAllocator("SurroundBlockAllocator");
                        allocator.Allocate(new BlockItem {
                            Ancestor = nodeNavigator.Current,
                            InconsistentBlocks = unallocatedBlocks
                        }, context);
                        }
                    if (unallocatedBlocks.Count > 0 && blockItemsCount > block.Count) {
                        IBlockAllocator allocator = context.GetBlockAllocator("InBlocksAllocator");
                        allocator.Allocate(new BlockItem {
                            Ancestor = nodeNavigator.Current,
                            InconsistentBlocks = unallocatedBlocks
                        }, context);
                        item.InconsistentBlocks.RemoveAt(i--);
                        break;
                        }
                    else if (block.Count == 0) {
                        item.InconsistentBlocks.RemoveAt(i--);
                        break;
                        }
                    else
                        block.Restore();
                    }
                }
            }

        private IList<InconsistentBlock> Arrange(IList<InconsistentBlock> blocks) {
            if (blocks.Count < 3) {
                return blocks;
                }
            else {
                IList<InconsistentBlock> result = new List<InconsistentBlock>();
                int middleLine = blocks.Count / 2;
                for (int k = 0; k <= middleLine; k++)
                    result.Add(blocks[k]);
                for (int k = blocks.Count - 1; k > middleLine; k--)
                    result.Add(blocks[k]);
                return result;
                }
            }
        }
    }
